package com.zhufeng.web.socket;

import com.alibaba.fastjson.JSONObject;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.DefaultHttpHeaders;
import io.netty.handler.codec.http.HttpClientCodec;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker;
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshakerFactory;
import io.netty.handler.codec.http.websocketx.WebSocketVersion;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import lombok.extern.slf4j.Slf4j;

import java.net.URI;

/**
 * @ClassName: NettyClient
 * @Description TODO
 * @author 月夜烛峰
 * @date 2022/9/23 10:38
 */
@Slf4j
public class NettyClient {

    public static void main(String[] args) throws Exception {

        // Netty 线程组
        EventLoopGroup group = new NioEventLoopGroup();

        // Netty 启动类
        Bootstrap boot = new Bootstrap();

        boot.option(ChannelOption.SO_KEEPALIVE, true)
                .option(ChannelOption.TCP_NODELAY, true)
                .group(group)
                .handler(new LoggingHandler(LogLevel.INFO))
                .channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        ChannelPipeline pipeline = socketChannel.pipeline();
                        pipeline.addLast("http-codec",new HttpClientCodec());
                        pipeline.addLast("aggregator",new HttpObjectAggregator(1024*1024*10));
                        pipeline.addLast("hookedHandler", new WebSocketClientHandler());
                    }
                });

        // 这里的路径即为网关中配置的路由路径
        URI webSocketURI = new URI("ws://localhost:9990/nio/info");
        //URI webSocketURI = new URI("ws://10.211.55:8880");
        System.out.println(webSocketURI.getHost()+","+webSocketURI.getPort());
        HttpHeaders httpHeaders = new DefaultHttpHeaders();

        // 握手
        WebSocketClientHandshaker handshaker = WebSocketClientHandshakerFactory.newHandshaker(webSocketURI, WebSocketVersion.V13, (String) null, true, httpHeaders);

        System.out.println(JSONObject.toJSONString(webSocketURI));
        // 连接通道
        final Channel channel = boot.connect(webSocketURI.getHost(), webSocketURI.getPort()).sync().channel();
        WebSocketClientHandler handler = (WebSocketClientHandler) channel.pipeline().get("hookedHandler");

        handler.setHandshaker(handshaker);
        handshaker.handshake(channel);

        // 阻塞等待是否握手成功
        handler.handshakeFuture().sync();

        // 给服务端发送的内容，如果客户端与服务端连接成功后，可以多次掉用这个方法发送消息
        sendMessage(channel);
    }

    private static void sendMessage(Channel channel){
        //发送的内容，是一个文本格式的内容

        // 此处NettyMsg为自定义消息解析器，setJsonMsg为设置一条Json串消息
        JSONObject userInfo = new JSONObject();
        userInfo.put("userId","u1001");
        userInfo.put("userName","月夜烛峰");


                TextWebSocketFrame frame = new TextWebSocketFrame(userInfo.toJSONString());
        channel.writeAndFlush(frame).addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture channelFuture) throws Exception {
                System.out.println("消息发送结果："+JSONObject.toJSONString(channelFuture));
                if (channelFuture.isSuccess()) {
                    System.out.println("消息发送成功，发送的消息是：" + userInfo.toJSONString());
                } else {
                    System.out.println("消息发送失败 " + channelFuture.cause().getMessage());
                }
            }
        });
    }

}
